package HW3;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

public class FileDownloadUtils {
    private static final int LOAD_NUM = 3;// 同时下载的线程数
    private static ThreadPoolExecutor executor;// 线程池
    private static final int sums[];// 记录每个线程下载的进度
    private static OnDownloadListener listener = null;
    private static int lastProgress = 0;// 记录上一个进度百分点
    private static int index = 0;
    static {
        sums = new int[LOAD_NUM];
        // 创建线程池
        executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(LOAD_NUM);
        executor.prestartAllCoreThreads();// 预加载线程

    }
    private static File dest;// 粘贴 的目标文件
    private static long fileLength;// 复制的文件总长度


    public static void downLoad(File url, File dir, OnDownloadListener l) {
        FileDownloadUtils.listener = l;// 回调函数
        final File src = url;
        fileLength = src.length();
        dest = new File(dir, src.getName());// 目标文件路径描述的对象
        setTemporaryFile(dest, src.length());// 开辟临时文件
        long start = 0;
        long end = 0;
        for (int i = 0; i < LOAD_NUM; i++) {
            start = end;
            if (i == LOAD_NUM - 1) {
                end = fileLength;
            } else {
                end = start + fileLength / LOAD_NUM;
            }
            LoadWorker loadWorker = new LoadWorker(src, dest, start, end, i);
            executor.execute(loadWorker);// 执行多线程，并开始下载
        }

    }


    private static synchronized void loadComplete() {
        index++;
        if (index >= LOAD_NUM) {
            // 下载完成
            if (listener != null) {
                listener.onComplete(dest);
                index = 0;
            }
        }
    }


    public interface OnDownloadListener {
        void onComplete(File file);// 文件下载完成通知

        void onProgress(int progress);// 下载进度通知
    }

    //设置临时文件

    private static void setTemporaryFile(File file, long length) {
        try (RandomAccessFile raf = new RandomAccessFile(file, "rw");) {
            raf.setLength(length);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //进度计算

    private static void progress() {

        if (listener != null) {
            long sunLength = 0;
            for (int i : sums) {
                sunLength += i;
            }
            // 当前进度百分点
            int progress = (int) (100.0 * sunLength / fileLength);
            if (progress > lastProgress) {// 当百分点发生变化，则通知接口回调
                // 防止多个线程同事 刷新同一个百分点
                synchronized (FileDownloadUtils.class) {
                    // 双重验证
                    if (progress > lastProgress) {// 通知进度
                        listener.onProgress(progress);// 记录上一个百分点
                        lastProgress = progress;
                    }
                }
            }
        }
    }

    private static class LoadWorker implements Runnable {
        private File src;// 拷贝的文件
        private File dest;// 粘贴的文件
        private long start;// 当前线程开始下载的位置
        private long end;// 当前线程结束下载的位置
        private int index = 0;// 记录该线程的编号，为了记录进度

        public LoadWorker(File src, File dest, long start, long end, int index) {
            super();
            this.src = src;
            this.dest = dest;
            this.start = start;
            this.end = end;
            this.index = index;
        }

        @Override
        public void run() {
            try (RandomAccessFile from = new RandomAccessFile(src, "r");
                 RandomAccessFile to = new RandomAccessFile(dest, "rw");) {

                from.seek(start);
                to.seek(start);
                byte[] b = new byte[1024];
                int len = b.length;
                int sum = 0;
                while (true) {
                    long poor = (end - start) - sum;
                    if (poor < b.length) {
                        len = (int) poor;
                    }
                    int read = from.read(b, 0, len);
                    to.write(b, 0, read);
                    sum += read;
                    sums[index] = sum;// 记录当前线程的下载进度
                    progress();// 更新进度
                    if (sum >= end - start) {
                        // 当前线程读取完毕
                        loadComplete();
                        break;
                    }
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

}
